import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { Queue } from 'bull';
import { InjectQueue } from '@nestjs/bull';
import * as path from 'path';
import { fsReadAllDir, fsReaddir } from './utils/fs';
import { InjectConnection, InjectRepository } from '@nestjs/typeorm';
import { FileInfo } from './entities/FileInfo';
import { Connection, Repository } from 'typeorm';
import { TransformClassToPlain } from 'class-transformer';
import { FileStorage } from './entities/FileStorage';
import * as fse from 'fs-extra';

@Injectable()
export class AppService {
    constructor(
        @InjectQueue('video') private queue: Queue,
        @InjectConnection() private connection: Connection,
        @InjectRepository(FileInfo) private fileInfo: Repository<FileInfo>,
        @InjectRepository(FileStorage) private fileStorage: Repository<FileStorage>,
    ) {
    }

    async addBulk(dirpath: string, targetpath: string, all = false) {
        if (all) {
            const files: string[] = await fsReadAllDir(dirpath);
            this.queue.addBulk(
                files
                    .map(filepath => ({
                        data: {
                            filepath,
                            dirpath,
                            targetpath,
                        },
                        opts: {
                            removeOnComplete: true,
                        },
                    })),
            );
        } else {
            const files: string[] = await fsReaddir(dirpath);
            this.queue.addBulk(
                files
                    .map(data => ({
                        data: {
                            filepath: path.resolve(dirpath, data),
                            dirpath,
                            targetpath,
                        },
                        opts: {
                            removeOnComplete: true,
                        },
                    })),
            );
        }
    }

    @TransformClassToPlain()
    async listVideo(pageNum: number, pageSize: number) {
        pageNum = pageNum > 1 && pageNum < Infinity ? pageNum : 1;
        const skip = (pageNum - 1) * pageSize;
        const take = pageSize > 10 && pageSize < 100 ? pageSize : 10;
        const [records, total] = await this.fileInfo.findAndCount({
            skip,
            take,
            order: {
                viewCount: 'ASC',
                createDate: 'DESC',
            },
            relations: ['fileStorage'],
        });
        return {
            records,
            total,
            pageNum,
            pageSize: take,
        };
    }

    async deleteFileInfo(md5?: string) {
        if (md5) {
            await this.connection.transaction(async manager => {
                await manager.delete<FileInfo>(
                    FileInfo,
                    {
                        fileStorage: {
                            md5,
                        },
                    },
                );
                const fileStorage = await manager.findOne<FileStorage>(FileStorage, {md5});
                if (fileStorage && !fileStorage.isDeleted) {
                    const update = await manager.update<FileStorage>(FileStorage, {md5}, {isDeleted: true});
                    await fse.unlink(fileStorage.filepath);
                }
            });
            return {
                message: '操作成功',
            };
        } else {
            throw new HttpException('参数错误', HttpStatus.BAD_REQUEST);
        }
    }

    @TransformClassToPlain()
    async getFileInfo(id?: string, md5?: string) {
        if (id) {
            return this.fileInfo.findOne({
                where: {
                    id,
                },
                relations: ['fileStorage'],
            });
        } else if (md5) {
            return this.fileInfo.findOne({
                where: {
                    fileStorage: {
                        md5,
                    },
                },
                relations: ['fileStorage'],
            });
        } else {
            throw new HttpException('参数错误', HttpStatus.BAD_REQUEST);
        }
    }

    updateFileInfo(id: string, entity: any) {
        if (id) {
            return this.fileInfo.update({id}, entity);
        }
        throw new HttpException('参数错误', HttpStatus.BAD_REQUEST);
    }
}
